package com.tsfyun.scm.service.impl.finance;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.draw.LineSeparator;
import com.tsfyun.common.base.dto.ExportFileDTO;
import com.tsfyun.common.base.dto.TaskDTO;
import com.tsfyun.common.base.enums.MailContentTypeEnum;
import com.tsfyun.common.base.enums.MailTemplateTypeEnum;
import com.tsfyun.common.base.enums.domain.*;
import com.tsfyun.common.base.enums.exp.CollectionSourceEnum;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.security.SecurityUtil;
import com.tsfyun.common.base.support.DomainStatus;
import com.tsfyun.common.base.util.*;
import com.tsfyun.common.base.validator.ValidatorUtils;
import com.tsfyun.scm.base.DataCalling;
import com.tsfyun.scm.dto.finance.*;
import com.tsfyun.scm.dto.support.TaskNoticeContentDTO;
import com.tsfyun.scm.entity.customer.Customer;
import com.tsfyun.scm.entity.finance.PurchaseContract;
import com.tsfyun.scm.entity.finance.PurchaseContractMember;
import com.tsfyun.scm.entity.order.ExpOrder;
import com.tsfyun.scm.entity.order.ExpOrderMember;
import com.tsfyun.scm.entity.system.Subject;
import com.tsfyun.scm.mapper.finance.PurchaseContractMapper;
import com.tsfyun.scm.service.common.ICommonService;
import com.tsfyun.scm.service.customer.ICustomerService;
import com.tsfyun.scm.service.file.IExportFileService;
import com.tsfyun.scm.service.finance.IPurchaseContractMemberService;
import com.tsfyun.scm.service.finance.IPurchaseContractService;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.scm.service.order.IExpOrderCostService;
import com.tsfyun.scm.service.order.IExpOrderMemberService;
import com.tsfyun.scm.service.order.IExpOrderService;
import com.tsfyun.scm.service.support.ITaskNoticeContentService;
import com.tsfyun.scm.service.system.IMailService;
import com.tsfyun.scm.service.system.IStatusHistoryService;
import com.tsfyun.scm.service.system.ISubjectBankService;
import com.tsfyun.scm.service.system.ISubjectService;
import com.tsfyun.scm.system.vo.CustomsCodeVO;
import com.tsfyun.scm.util.TsfWeekendSqls;
import com.tsfyun.scm.vo.finance.*;
import com.tsfyun.scm.vo.order.ExpOrderCostVO;
import com.tsfyun.scm.vo.order.ExpOrderMemberVO;
import com.tsfyun.scm.vo.system.SubjectBankVO;
import com.tsfyun.scm.vo.system.SubjectVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 采购合同 服务实现类
 * </p>
 *
 *
 * @since 2021-09-26
 */
@Slf4j
@Service
public class PurchaseContractServiceImpl extends ServiceImpl<PurchaseContract> implements IPurchaseContractService {

    @Autowired
    private PurchaseContractMapper purchaseContractMapper;
    @Autowired
    private IPurchaseContractMemberService purchaseContractMemberService;
    @Autowired
    private ICustomerService customerService;
    @Autowired
    private IExpOrderCostService expOrderCostService;
    @Autowired
    private IExpOrderService expOrderService;
    @Autowired
    private ISubjectService subjectService;
    @Autowired
    private ISubjectBankService subjectBankService;
    @Autowired
    private IExpOrderMemberService expOrderMemberService;
    @Autowired
    private Snowflake snowflake;
    @Autowired
    private IStatusHistoryService statusHistoryService;
    @Autowired
    private ITaskNoticeContentService taskNoticeContentService;
    @Autowired
    private ICommonService commonService;
    @Value("${file.directory}")
    private String filePath;
    @Autowired
    private IExportFileService exportFileService;
    @Autowired
    private IMailService mailService;
    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public PageInfo<PurchaseContractVO> pageList(PurchaseContractQTO qto) {
        //如果传了动态日期字段，检查是否包含该字段以防数据库报错
        if(StringUtils.isNotEmpty(qto.getQueryDate())) {
            TsfPreconditions.checkArgument(ClassUtil.containsField(PurchaseContract.class,qto.getQueryDate()),new ServiceException("日期查询类型参数错误"));
        }
        PageHelper.startPage(qto.getPage(),qto.getLimit());
        Map<String,Object> params = beanMapper.map(qto, Map.class);
        List<PurchaseContractVO> list = purchaseContractMapper.list(params);
        return new PageInfo<>(list);
    }

    @Override
    public PurchaseContractPlusVO detailPlus(Long id,String operation) {
        return detailPlus(id,operation,Boolean.TRUE);
    }

    @Override
    public PurchaseContractPlusVO detailPlus(Long id, String operation, Boolean queryCost) {
        PurchaseContract purchaseContract = super.getById(id);
        Optional.ofNullable(purchaseContract).orElseThrow(()->new ServiceException("采购合同不存在"));
        DomainStatus.getInstance().check(DomainOprationEnum.of(operation),purchaseContract.getStatusId());
        Customer customer = customerService.getById(purchaseContract.getCustomerId());
        Optional.ofNullable(customer).orElseThrow(()->new ServiceException("客户信息不存在"));
        PurchaseContractVO purchaseContractVO = beanMapper.map(purchaseContract,PurchaseContractVO.class);
        purchaseContractVO.setEffectiveDate(DateUtils.addYear(purchaseContractVO.getSigningDate(),1));
        ExpOrder expOrder = expOrderService.findByDocNo(purchaseContract.getOrderNo());
        ValidatorUtils.isTrueCall(Objects.nonNull(expOrder),()->{
            purchaseContractVO.setCustomerOrderNo(expOrder.getClientNo());
        });
        String tempYear = DateUtils.format(purchaseContractVO.getSigningDate(),"yyyy");
        purchaseContractVO.setDeliveryDate(DateUtils.parseShort(StrUtil.format("{}-12-31",tempYear)));

        purchaseContractVO.setCustomerName(customer.getName());
        List<PurchaseContractMember> members = purchaseContractMemberService.findByPurchaseContractId(id);
        List<PurchaseContractMemberVO> memberVOs = beanMapper.mapAsList(members, PurchaseContractMemberVO.class);

        List<ExpOrderMember> expOrderMembers = expOrderMemberService.getByOrderId(purchaseContract.getOrderId());
        Map<Long,ExpOrderMember> expOrderMemberMap = expOrderMembers.stream().collect(Collectors.toMap(ExpOrderMember::getId,Function.identity()));
        memberVOs.stream().forEach(purchaseContractMemberVO -> {
            ExpOrderMember expOrderMember = expOrderMemberMap.get(purchaseContractMemberVO.getOrderMemberId());
            ValidatorUtils.isTrueCall(Objects.nonNull(expOrderMember),()->{
                purchaseContractMemberVO.setNetWeight(expOrderMember.getNetWeight());
                purchaseContractMemberVO.setGrossWeight(expOrderMember.getGrossWeight());
                purchaseContractMemberVO.setCartonNum(expOrderMember.getCartonNum());
            });
        });
        PurchaseContractPlusVO purchaseContractPlusVO = new PurchaseContractPlusVO(purchaseContractVO,memberVOs);

        if(Objects.equals(queryCost,Boolean.TRUE)) {
            List<String> collectionSources = Lists.newArrayList(CollectionSourceEnum.DEDUCTION.getCode());
            List<ExpOrderCostVO> costMembers = expOrderCostService.findCostByOrderIdAndCollectionSource(purchaseContract.getOrderId(), collectionSources);
            purchaseContractPlusVO.setCostMembers(costMembers);
        }
        return purchaseContractPlusVO;
}

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        PurchaseContract purchaseContract = super.getById(id);
        Optional.ofNullable(purchaseContract).orElseThrow(()->new ServiceException("采购合同不存在"));
        DomainStatus.getInstance().check(DomainOprationEnum.PURCHASE_CONTRACT_REMOVE,purchaseContract.getStatusId());
        // 删除合同明细
        purchaseContractMemberService.removeByContractId(id);
        // 修改订单
        ExpOrder update = new ExpOrder();
        update.setId(purchaseContract.getOrderId());
        update.setPurchaseContractNo("");
        update.setPurchaseCny(BigDecimal.ZERO);
        update.setAdjustmentVal(BigDecimal.ZERO);
        update.setDifferenceVal(BigDecimal.ZERO);
        expOrderService.updateByPurchaseContract(update);
        // 删除合同主单
        super.removeById(id);
        //删除历史状态
        statusHistoryService.removeHistory(purchaseContract.getId().toString(), PurchaseContract.class.getName());
        // 清空任务
        clearTaskNotice(id);
    }

    @Override
    public CreateContractPlusVO createByOrderId(Long orderId) {
        ExpOrder order = expOrderService.getById(orderId);
        if(Objects.isNull(order) || StringUtils.isNotEmpty(order.getPurchaseContractNo())){
            throw new ServiceException("订单不存在或已经生成采购合同");
        }
        //验证状态是否可以执行操作
        DomainStatus.getInstance().check(DomainOprationEnum.CREATE_PURCHASE_CONTRACT, order.getStatusId());
        Customer customer = customerService.getById(order.getCustomerId());
        CreateContractMainVO main = new CreateContractMainVO();
        main.setCustomerId(customer.getId());
        main.setCustomerName(customer.getName());
        main.setOrderId(order.getId());
        main.setOrderNo(order.getDocNo());
        main.setSigningDate(DateUtils.addDays(LocalDateTimeUtils.convertLDTToDate(order.getOrderDate()),-15));
        main.setSigningPlace("深圳特区");
        Subject subject = subjectService.getById(order.getSubjectId());
        main.setBuyerName(subject.getName());
        main.setBuyerDeputy(subject.getLegalPerson());
        main.setBuyerTel(subject.getTel());
        List<SubjectBankVO> subjectBankVOS = subjectBankService.selectEnableBanks();
        if(CollectionUtil.isNotEmpty(subjectBankVOS)){
            main.setBuyerBank(subjectBankVOS.get(0).getName());
            main.setBuyerBankNo(subjectBankVOS.get(0).getAccount());
            //main.setBuyerBankAddress(subjectBankVOS.get(0).getAddress());
            //改成存买方地址
            main.setBuyerBankAddress(subject.getAddress());
        }
        main.setSellerName(customer.getName());
        main.setSellerDeputy(customer.getLegalPerson());
        main.setSellerTel(customer.getTel());
        main.setSellerBank(customer.getInvoiceBankName());
        main.setSellerBankNo(customer.getInvoiceBankAccount());
        //main.setSellerBankAddress(customer.getInvoiceBankAddress());
        //改成存卖方地址
        main.setSellerBankAddress(customer.getAddress());

        main.setIsSettleAccount(order.getIsSettleAccount());
        if(Objects.equals(order.getIsSettleAccount(),Boolean.TRUE)){
            // 结汇完成
            main.setExchangeRate(BigDecimal.ZERO);
            main.setSettleAccountInfo("创建采购合同时：已结汇，按照结汇金额计算采购合同金额");
            main.setSettleAccountCny(order.getSettleAccountCny());
        }else{
            main.setExchangeRate(order.getCustomsRate());
            main.setSettleAccountInfo("创建采购合同时：未结汇，根据预估汇率计算采购合同金额");
            main.setSettleAccountCny(BigDecimal.ZERO);
        }
        main.setCurrencyId(order.getCurrencyId());
        main.setCurrencyName(order.getCurrencyName());
        main.setTotalDifferenceVal(BigDecimal.ZERO);
        main.setDifferenceVal(BigDecimal.ZERO);
        CreateContractPlusVO vo = new CreateContractPlusVO();
        vo.setMain(main);
        calculationMember(vo);
        return vo;
    }

    @Override
    public BigDecimal calculationActualPurchaseValue(Long orderId, BigDecimal settlementValue) {
        CreateContractMainVO main = new CreateContractMainVO();
        main.setOrderId(orderId);
        main.setIsSettleAccount(Boolean.TRUE);
        main.setSettleAccountCny(settlementValue);
        main.setDifferenceVal(BigDecimal.ZERO);
        CreateContractPlusVO vo = new CreateContractPlusVO();
        vo.setMain(main);
        calculationMember(vo);
        return main.getTotalPrice();
    }

    @Override
    public CreateContractPlusVO recalculate(PurchaseContractDTO dto) {
        CreateContractMainVO main = fullData(dto);
        CreateContractPlusVO vo = new CreateContractPlusVO();
        vo.setMain(main);
        calculationMember(vo);
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(PurchaseContractDTO dto) {
        CreateContractPlusVO vo = recalculate(dto);
        CreateContractMainVO main = vo.getMain();
        PurchaseContract contract = beanMapper.map(main,PurchaseContract.class);
        contract.setDocNo(dto.getDocNo());
        contract.setInvoiceVal(BigDecimal.ZERO);
        // 待确认
        PurchaseContractStatusEnum statusEnum = PurchaseContractStatusEnum.WAIT_CONFIRM;
        contract.setStatusId(statusEnum.getCode());
        super.saveNonNull(contract);
        List<CreateContractMemberVO> members = vo.getMembers();
        List<PurchaseContractMember> purchaseContractMembers = new ArrayList<>();
        for(CreateContractMemberVO memberVO : members){
            PurchaseContractMember member = beanMapper.map(memberVO,PurchaseContractMember.class);
            member.setPurchaseContractId(contract.getId());
            member.setId(snowflake.nextId());
            purchaseContractMembers.add(member);
        }
        purchaseContractMemberService.savaBatch(purchaseContractMembers);
        // 修改订单
        ExpOrder update = new ExpOrder();
        update.setId(contract.getOrderId());
        update.setPurchaseContractNo(contract.getDocNo());
        update.setPurchaseCny(contract.getTotalPrice());// 采购合同总价
        update.setAdjustmentVal(contract.getDifferenceVal());// 票差调整金额
        update.setDifferenceVal(BigDecimal.ZERO);// 生成的票差金额
        expOrderService.updateByPurchaseContract(update);

        //记录历史状态
        statusHistoryService.saveHistory(DomainOprationEnum.PURCHASE_CONTRACT_ADD,
                contract.getId().toString(), PurchaseContract.class.getName(),
                statusEnum.getCode(),statusEnum.getName(),"创建采购合同"
        );

        //发送任务通知
        TaskNoticeContentDTO taskNoticeContentDTO = new TaskNoticeContentDTO();
        taskNoticeContentDTO.setDocumentType(DomainTypeEnum.PURCHASECONTRACT.getCode());
        taskNoticeContentDTO.setDocumentId(contract.getId().toString());
        taskNoticeContentDTO.setCustomerId(contract.getCustomerId());
        taskNoticeContentDTO.setOperationCode(DomainOprationEnum.PURCHASE_CONTRACT_CONFIRM.getCode());
        taskNoticeContentDTO.setContent(String.format("采购合同【%s】需要您确认",contract.getDocNo()));
        taskNoticeContentDTO.setQueryParamsMap(ImmutableMap.of("docNo",contract.getDocNo()));
        taskNoticeContentService.add(taskNoticeContentDTO);
    }

    public CreateContractMainVO fullData(PurchaseContractDTO dto){
        ExpOrder order = expOrderService.getById(dto.getOrderId());
        if(Objects.isNull(order) || StringUtils.isNotEmpty(order.getPurchaseContractNo())){
            throw new ServiceException("订单不存在或已经生成采购合同");
        }
        //验证状态是否可以执行操作
        DomainStatus.getInstance().check(DomainOprationEnum.CREATE_PURCHASE_CONTRACT, order.getStatusId());
        CreateContractMainVO main = new CreateContractMainVO();
        if(Objects.equals(order.getIsSettleAccount(),Boolean.TRUE)){
            // 结汇完成
            main.setExchangeRate(BigDecimal.ZERO);
            main.setSettleAccountInfo("创建采购合同时：已结汇，按照结汇金额计算采购合同金额");
            main.setSettleAccountCny(order.getSettleAccountCny());
        }else{
            main.setExchangeRate(dto.getExchangeRate());
            main.setSettleAccountInfo("创建采购合同时：未结汇，根据预估汇率计算采购合同金额");
            main.setSettleAccountCny(BigDecimal.ZERO);
        }
        Customer customer = customerService.getById(order.getCustomerId());
        main.setCustomerId(customer.getId());
        main.setCustomerName(customer.getName());
        main.setOrderId(order.getId());
        main.setOrderNo(order.getDocNo());
        main.setSigningDate(dto.getSigningDate());
        main.setSigningPlace(dto.getSigningPlace());
        Subject subject = subjectService.getById(order.getSubjectId());
        main.setBuyerName(subject.getName());
        main.setBuyerDeputy(dto.getBuyerDeputy());
        main.setBuyerTel(dto.getBuyerTel());
        main.setBuyerBank(dto.getBuyerBank());
        main.setBuyerBankNo(dto.getBuyerBankNo());
        main.setBuyerBankAddress(dto.getBuyerBankAddress());
        main.setSellerName(customer.getName());
        main.setSellerDeputy(dto.getSellerDeputy());
        main.setSellerTel(dto.getSellerTel());
        main.setSellerBank(dto.getSellerBank());
        main.setSellerBankNo(dto.getSellerBankNo());
        main.setSellerBankAddress(dto.getSellerBankAddress());
        main.setIsSettleAccount(order.getIsSettleAccount());
        main.setCurrencyId(order.getCurrencyId());
        main.setCurrencyName(order.getCurrencyName());
        main.setTotalDifferenceVal(BigDecimal.ZERO);
        main.setDifferenceVal(dto.getDifferenceVal());
        return main;
    }

    // 计算明细金额
    public void calculationMember(CreateContractPlusVO vo){
        List<String> collectionSources = Lists.newArrayList(CollectionSourceEnum.DEDUCTION.getCode());
        // 获取订单费用
        List<ExpOrderCostVO> orderCosts = expOrderCostService.findCostByOrderIdAndCollectionSource(vo.getMain().getOrderId(), collectionSources);
        vo.setOrderCosts(orderCosts);
        // 代理费金额
        BigDecimal agencyFee = BigDecimal.ZERO;
        // 其它杂费
        BigDecimal otherFee = BigDecimal.ZERO;
        for(ExpOrderCostVO cost : orderCosts){
            if("A0001".equals(cost.getExpenseSubjectId())){
                agencyFee = agencyFee.add(cost.getReceAmount()).setScale(2,BigDecimal.ROUND_HALF_UP);
            }else{
                otherFee = otherFee.add(cost.getReceAmount()).setScale(2,BigDecimal.ROUND_HALF_UP);
            }
        }
        vo.getMain().setAgentFee(agencyFee);
        vo.getMain().setMatFee(otherFee);
        //获取包含归类物料的产品信息
        List<ExpOrderMemberVO> expOrderMemberVOS = expOrderMemberService.findOrderMaterielMember(vo.getMain().getOrderId());
        //存储海关编码
        Map<String, CustomsCodeVO> hsCodeMap = Maps.newHashMap();
        List<CreateContractMemberVO> members = new ArrayList<>();
        // 订单总报关金额
        BigDecimal totalPrice = expOrderMemberVOS.stream().map(ExpOrderMemberVO::getDecTotalPrice).reduce(BigDecimal.ZERO,BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal totalSettleAccountCny = BigDecimal.ZERO;//分摊后总结汇人民币金额
        for(ExpOrderMemberVO member : expOrderMemberVOS) {
            //物料未归类
            if (!Objects.equals(MaterielStatusEnum.of(member.getMaterielStatusId()), MaterielStatusEnum.CLASSED)) {
                throw new ServiceException(String.format("第【%d】行：【%s】【%s】【%s】还未完成归类", member.getRowNo(), member.getName(), member.getBrand(), member.getModel()));
            }
            //获取海关编码详情
            CustomsCodeVO customsCodeVO = hsCodeMap.get(member.getHsCode());
            if(Objects.isNull(customsCodeVO)){
                customsCodeVO = DataCalling.getInstance().obtainHsCodeDetail(member.getHsCode());
                hsCodeMap.put(member.getHsCode(),customsCodeVO);
            }
            if(Objects.isNull(customsCodeVO)){
                throw new ServiceException(String.format("第【%d】行：【%s】【%s】【%s】未找到海关编码数据", member.getRowNo(), member.getName(), member.getBrand(), member.getModel()));
            }
            CreateContractMemberVO cmvo = new CreateContractMemberVO();
            cmvo.setRowNo(member.getRowNo());
            cmvo.setOrderMemberId(member.getId());
            cmvo.setModel(member.getModel());
            cmvo.setBrand(member.getBrand());
            cmvo.setName(member.getName());
            cmvo.setUnitCode(member.getUnitCode());
            cmvo.setUnitName(member.getUnitName());
            cmvo.setQuantity(member.getQuantity());
            cmvo.setDecTotalPrice(member.getDecTotalPrice());
            cmvo.setAddedTaxRate(customsCodeVO.getVatr().divide(new BigDecimal(100)));
            try{
                cmvo.setTaxRebateRate(new BigDecimal(customsCodeVO.getTrr()).divide(new BigDecimal(100)));
            }catch (Exception e){
                throw new ServiceException(String.format("第【%d】行：【%s】【%s】【%s】【%s】海关编码退税率错误", member.getRowNo(),member.getHsCode(), member.getName(), member.getBrand(), member.getModel()));
            }
            // 计算分摊比列
            BigDecimal billie = member.getTotalPrice().divide(totalPrice,20,BigDecimal.ROUND_HALF_UP);
            // 代理费
            cmvo.setAgentFee(agencyFee.multiply(billie).setScale(2,BigDecimal.ROUND_HALF_UP));
            // 代垫费
            cmvo.setMatFee(otherFee.multiply(billie).setScale(2,BigDecimal.ROUND_HALF_UP));
            // 票差
            cmvo.setDifferenceVal(vo.getMain().getDifferenceVal().multiply(billie).setScale(2,BigDecimal.ROUND_HALF_UP));

            if(Objects.equals(vo.getMain().getIsSettleAccount(),Boolean.TRUE)){
                // 已结汇
                cmvo.setSettlementValue(vo.getMain().getSettleAccountCny().multiply(billie).setScale(2,BigDecimal.ROUND_HALF_UP));
                cmvo.setSettlementValueCny(cmvo.getSettlementValue());
                totalSettleAccountCny = totalSettleAccountCny.add(cmvo.getSettlementValue()).setScale(2,BigDecimal.ROUND_HALF_UP);
            }else{
                // 未结汇
                cmvo.setSettlementValueCny(BigDecimal.ZERO);
                cmvo.setSettlementValue(cmvo.getDecTotalPrice().multiply(vo.getMain().getExchangeRate()));
            }
            members.add(cmvo);
        }
        if(Objects.equals(vo.getMain().getIsSettleAccount(),Boolean.TRUE)){
            members.get(0).setSettlementValue(members.get(0).getSettlementValue().add(vo.getMain().getSettleAccountCny().subtract(totalSettleAccountCny)).setScale(2,BigDecimal.ROUND_HALF_UP));
        }
        BigDecimal totalAgentFee = BigDecimal.ZERO;
        BigDecimal totalMatFee = BigDecimal.ZERO;
        BigDecimal totalDifferenceVal = BigDecimal.ZERO;
        for(CreateContractMemberVO memberVO : members){
            totalAgentFee = totalAgentFee.add(memberVO.getAgentFee()).setScale(2,BigDecimal.ROUND_HALF_UP);
            totalMatFee = totalMatFee.add(memberVO.getMatFee()).setScale(2,BigDecimal.ROUND_HALF_UP);
            totalDifferenceVal = totalDifferenceVal.add(memberVO.getDifferenceVal()).setScale(2,BigDecimal.ROUND_HALF_UP);
        }
        members.get(0).setAgentFee(members.get(0).getAgentFee().add(agencyFee.subtract(totalAgentFee)).setScale(2,BigDecimal.ROUND_HALF_UP));
        members.get(0).setMatFee(members.get(0).getMatFee().add(otherFee.subtract(totalMatFee)).setScale(2,BigDecimal.ROUND_HALF_UP));
        members.get(0).setDifferenceVal(members.get(0).getDifferenceVal().add(vo.getMain().getDifferenceVal().subtract(totalDifferenceVal)).setScale(2,BigDecimal.ROUND_HALF_UP));
        BigDecimal mainTotalPrice = BigDecimal.ZERO;
        for(CreateContractMemberVO memberVO : members){
            // 采购总价=(外贸合同总价*预估汇率-代理费-代垫费)*(1+增值税率)/(1+增值税率-退税率)+票差
            memberVO.setTotalPrice((memberVO.getSettlementValue().subtract(memberVO.getAgentFee()).subtract(memberVO.getMatFee())).multiply(
                    (BigDecimal.ONE.add(memberVO.getAddedTaxRate())).divide(BigDecimal.ONE.add(memberVO.getAddedTaxRate()).subtract(memberVO.getTaxRebateRate()),20,BigDecimal.ROUND_HALF_UP)
            ).add(memberVO.getDifferenceVal()).setScale(2,BigDecimal.ROUND_HALF_UP));
            // 单价
            memberVO.setUnitPrice(memberVO.getTotalPrice().divide(memberVO.getQuantity(),6,BigDecimal.ROUND_HALF_UP));

            mainTotalPrice = mainTotalPrice.add(memberVO.getTotalPrice()).setScale(2,BigDecimal.ROUND_HALF_UP);
        }
        vo.getMain().setTotalPrice(mainTotalPrice);
        vo.setMembers(members);
    }

    @Override
    public void confirm(TaskDTO dto) {
        commonService.changeDocumentStatus(dto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmInvoice(PurchaseInvoiceDTO dto) {
        PurchaseContract purchaseContract = super.getById(dto.getId());
        Optional.ofNullable(purchaseContract).orElseThrow(()->new ServiceException("采购合同不存在"));
        DomainStatus.getInstance().check(DomainOprationEnum.PURCHASE_CONTRACT_INVOICE,purchaseContract.getStatusId());
        purchaseContract.setInvoicingDate(dto.getInvoicingDate());
        purchaseContract.setInvoiceDate(dto.getInvoiceDate());
        purchaseContract.setInvoiceVal(dto.getInvoiceVal());
        purchaseContract.setInvoiceNo(dto.getInvoiceNo());
        PurchaseContractStatusEnum historyStatus = PurchaseContractStatusEnum.of(purchaseContract.getStatusId());
        // 收票完成
        PurchaseContractStatusEnum nowStatusEnum = PurchaseContractStatusEnum.COMPLETE;
        purchaseContract.setStatusId(nowStatusEnum.getCode());
        super.updateById(purchaseContract);
        //记录历史状态
        statusHistoryService.saveHistory(DomainOprationEnum.PURCHASE_CONTRACT_INVOICE,
                purchaseContract.getId().toString(),PurchaseContract.class.getName(),
                historyStatus.getCode(),historyStatus.getName(),
                nowStatusEnum.getCode(),nowStatusEnum.getName(),String.format("采购合同收票，收票金额：%s",StringUtils.formatCurrency(purchaseContract.getInvoiceVal()))
        );
        // 计算订单可退税金额
        ExpOrder expOrder = expOrderService.getById(purchaseContract.getOrderId());
        if(Objects.equals(expOrder.getIsSettleAccount(),Boolean.TRUE)){
            //结汇完成 退税金额=收票金额-结汇金额-代理费-代垫费
            // 调整为 退税金额=收票金额-结汇金额
            /*
            expOrder.setActualDrawbackValue(
                    purchaseContract.getInvoiceVal().subtract(expOrder.getSettleAccountCny()).subtract(purchaseContract.getAgentFee()).subtract(purchaseContract.getMatFee()).setScale(2,BigDecimal.ROUND_HALF_UP)
            );
             */
            expOrder.setActualDrawbackValue(
                    purchaseContract.getInvoiceVal().subtract(expOrder.getSettleAccountCny()).setScale(2,BigDecimal.ROUND_HALF_UP)
            );
        }else{
            //结汇未完成 退税金额=收票金额-(报关金额*预估汇率)-代理费-代垫费
            // 调整为 退税金额=收票金额-(报关金额*预估汇率)
            /*
            expOrder.setActualDrawbackValue(
                    purchaseContract.getInvoiceVal().subtract(expOrder.getDecTotalPrice().multiply(purchaseContract.getExchangeRate()).setScale(2,BigDecimal.ROUND_HALF_UP)).subtract(purchaseContract.getAgentFee()).subtract(purchaseContract.getMatFee()).setScale(2,BigDecimal.ROUND_HALF_UP)
            );
             */
            expOrder.setActualDrawbackValue(
                    purchaseContract.getInvoiceVal().subtract(expOrder.getDecTotalPrice().multiply(purchaseContract.getExchangeRate()).setScale(2,BigDecimal.ROUND_HALF_UP))
            );
        }
        expOrderService.updateById(expOrder);
        // 订单费用置位已收款
        expOrderCostService.purchaseInvoiceCompleted(expOrder.getId());
    }
    @Override
    public CreateDrawbackPlusVO initDrawback(List<Long> ids) {
        return initDrawback(ids,BigDecimal.valueOf(100));
    }
    @Override
    public CreateDrawbackPlusVO initDrawback(List<Long> ids,BigDecimal billie) {
        if(billie.compareTo(BigDecimal.ZERO) != 1){
            throw new ServiceException("本次退税比例必须大于零");
        }
        if(billie.compareTo(BigDecimal.valueOf(100)) >= 1){
            throw new ServiceException("本次退税比例最多100%");
        }
        CreateDrawbackVO drawback = new CreateDrawbackVO();
        List<PurchaseContract> purchaseContractList = purchaseContractMapper.findByIds(ids);
        if(CollectionUtil.isEmpty(purchaseContractList)){
            throw new ServiceException("请至少选择一个采购合同做退税申请");
        }
        drawback.setAccountValue(BigDecimal.ZERO);
        drawback.setBillie(billie);
        List<DrawbackOrderVO> orderList = new ArrayList<>();
        List<String> orderNos = new ArrayList<>();
        List<String> purchaseNos = new ArrayList<>();
        for(PurchaseContract contract : purchaseContractList){
            if(!Objects.equals(PurchaseContractStatusEnum.COMPLETE,PurchaseContractStatusEnum.of(contract.getStatusId()))){
                throw new ServiceException(String.format("采购合同【%s】还未完成收票无法退税",contract.getDocNo()));
            }
            ExpOrder expOrder = expOrderService.getById(contract.getOrderId());
            if(expOrder.getActualDrawbackValue().compareTo(expOrder.getAlreadyDrawbackValue()) == 0){
                throw new ServiceException(String.format("出口订单【%s】已完成退税无法再次申请退税",expOrder.getDocNo()));
            }
            DrawbackOrderVO orderVO = new DrawbackOrderVO();
            orderVO.setPurchaseId(contract.getId());
            orderVO.setPurchaseNo(contract.getDocNo());
            orderVO.setOrderId(contract.getOrderId());
            orderVO.setOrderNo(contract.getOrderNo());
            orderVO.setOrderDate(expOrder.getOrderDate());
            orderVO.setOrderTotalPrice(expOrder.getDecTotalPrice());
            orderVO.setOrderCurrencyName(expOrder.getCurrencyName());
            orderVO.setPurchaseTotalPrice(contract.getTotalPrice());// 采购金额
            orderVO.setInvoiceValue(contract.getInvoiceVal());// 收票金额
            orderVO.setIsSettleAccount(expOrder.getIsSettleAccount());// 是否结汇完成
            orderVO.setSettlementValue(expOrder.getSettleAccountCny());// 结汇金额
            orderVO.setDeductionValue(contract.getMatFee());// 代垫金额
            orderVO.setAgencyFee(contract.getAgentFee());// 代理费金额
            orderVO.setActualDrawbackValue(expOrder.getActualDrawbackValue());// 应退税金额
            orderVO.setAlreadyDrawbackValue(expOrder.getAlreadyDrawbackValue());// 已退税金额
            orderVO.setEstimatedPayment(BigDecimal.ZERO);
            if(Objects.equals(orderVO.getIsSettleAccount(),Boolean.FALSE)){
                orderVO.setEstimatedPayment(expOrder.getDecTotalPrice().multiply(contract.getExchangeRate()).setScale(2,BigDecimal.ROUND_HALF_UP));
            }
            // 退税金额=(应退税金额-已退税金额)*退税比例
            orderVO.setDrawbackValue(
                    (orderVO.getActualDrawbackValue().subtract(orderVO.getAlreadyDrawbackValue())).multiply(
                            drawback.getBillie().divide(BigDecimal.valueOf(100))
                    ).setScale(2,BigDecimal.ROUND_HALF_UP)
            );

            if(Objects.isNull(drawback.getCustomerId())){
                drawback.setCustomerId(contract.getCustomerId());
            }else{
                if(!Objects.equals(drawback.getCustomerId(),contract.getCustomerId())){
                    throw new ServiceException("请选择同一客户批量申请退税");
                }
            }
            orderList.add(orderVO);
            orderNos.add(orderVO.getOrderNo());
            purchaseNos.add(orderVO.getPurchaseNo());
            drawback.setAccountValue(drawback.getAccountValue().add(orderVO.getDrawbackValue()).setScale(2,BigDecimal.ROUND_HALF_UP));
        }
        drawback.setOrderNo(String.join(",",orderNos));
        drawback.setPurchaseNo(String.join(",",purchaseNos));
        List<String> clientNos = expOrderService.findClientNoByDocNos(orderNos);
        drawback.setClientNo(String.join(",",clientNos));
        Customer customer = customerService.getById(drawback.getCustomerId());
        drawback.setCustomerName(customer.getName());
        drawback.setPayeeName(customer.getName());
        CreateDrawbackPlusVO result = new CreateDrawbackPlusVO();
        result.setDrawback(drawback);
        result.setOrders(orderList);
        return result;
    }

    @Override
    public PurchaseContract findByDocNo(String docNo) {
        return purchaseContractMapper.selectOneByExample(Example.builder(PurchaseContract.class).where(TsfWeekendSqls.<PurchaseContract>custom()
                .andEqualTo(false,PurchaseContract::getDocNo,docNo)).build());
    }

    @Override
    public PurchaseContract findByExpOrderNo(String expOrderNo) {
        return purchaseContractMapper.selectOneByExample(Example.builder(PurchaseContract.class).where(TsfWeekendSqls.<PurchaseContract>custom()
                .andEqualTo(false,PurchaseContract::getOrderNo,expOrderNo)).build());
    }

    @Override
    public ExpInvoiceNotificationVO obtainExpInvoiceNotificationData(String expOrderNo) {
        ExpOrder expOrder = expOrderService.findByDocNo(expOrderNo);

        Optional.ofNullable(expOrder).orElseThrow(()->new ServiceException("订单信息不存在"));
        //获取采购合同信息
        PurchaseContract purchaseContract = findByExpOrderNo(expOrderNo);
        Optional.ofNullable(purchaseContract).orElseThrow(()->new ServiceException("订单还未做采购合同"));
        ExpInvoiceNotificationVO expInvoiceNotification = new ExpInvoiceNotificationVO();
        SubjectVO subject = subjectService.findByCode();
        expInvoiceNotification.setSubjectName(subject.getName());
        expInvoiceNotification.setSubjectAddress(subject.getAddress());
        expInvoiceNotification.setSubjectSocialNo(subject.getSocialNo());
        expInvoiceNotification.setSubjectBankName(purchaseContract.getBuyerBank());
        expInvoiceNotification.setSubjectBankNo(purchaseContract.getBuyerBankNo());
        expInvoiceNotification.setExpOrderNo(purchaseContract.getOrderNo());
        expInvoiceNotification.setDecDate(expOrder.getOrderDate());
        expInvoiceNotification.setExpAmount(expOrder.getTotalPrice());
        expInvoiceNotification.setPurchaseContractAmount(purchaseContract.getTotalPrice());
        expInvoiceNotification.setAgentAmount(purchaseContract.getAgentFee());
        expInvoiceNotification.setOtherAmount(purchaseContract.getMatFee());
        expInvoiceNotification.setCurrencyCode(expOrder.getCurrencyId());
        expInvoiceNotification.setCustomerName(purchaseContract.getSellerName());
        expInvoiceNotification.setExpOrderNo(expOrderNo);

        List<ExpInvoiceNotificationVO.ExpInvoiceNotificationMember> members = Lists.newArrayList();
        List<PurchaseContractMember> purchaseMembers = purchaseContractMemberService.findByPurchaseContractId(purchaseContract.getId());
        //获取订单明细数据
        List<ExpOrderMemberVO> expOrderMemberVOS = expOrderMemberService.findOrderMaterielMember(expOrder.getId());
        //按订单明细id转成map
        Map<Long,ExpOrderMemberVO> expOrderMemberMap = expOrderMemberVOS.stream().collect(Collectors.toMap(ExpOrderMemberVO::getId, Function.identity()));
        purchaseMembers.stream().forEach(purchaseContractMember -> {
            ExpInvoiceNotificationVO.ExpInvoiceNotificationMember member =  new ExpInvoiceNotificationVO.ExpInvoiceNotificationMember();
            member.setGoodsName(purchaseContractMember.getName());
            member.setGoodsBrand(purchaseContractMember.getBrand());
            member.setGoodsModel(purchaseContractMember.getModel());
            member.setQuantity(purchaseContractMember.getQuantity());
            member.setUnitName(purchaseContractMember.getUnitName());
            ExpOrderMemberVO expOrderMemberVO = expOrderMemberMap.get(purchaseContractMember.getOrderMemberId());
            member.setExpUnitPrice(expOrderMemberVO.getDecUnitPrice());
            member.setExpTotalPrice(expOrderMemberVO.getDecTotalPrice());
            member.setPurchaseContractUnitPrice(purchaseContractMember.getUnitPrice());
            member.setPurchaseContractAmount(purchaseContractMember.getTotalPrice());

            // 计算分摊比列
            BigDecimal billie = purchaseContractMember.getTotalPrice().divide(purchaseContract.getTotalPrice(),20,BigDecimal.ROUND_HALF_UP);
            //根据订单已结汇款人民币分摊明细
            if(Objects.nonNull(expOrder.getSettleAccountCny())) {
                member.setSettlementAccountCny(expOrder.getSettleAccountCny().multiply(billie).setScale(2,BigDecimal.ROUND_HALF_UP));
            } else {
                member.setSettlementAccountCny(BigDecimal.ZERO);
            }
            members.add(member);
        });
        BigDecimal totalSettlementAccountCny = StringUtils.rounded2(members.stream().map(ExpInvoiceNotificationVO.ExpInvoiceNotificationMember::getSettlementAccountCny).reduce(BigDecimal.ZERO,BigDecimal::add));
        //抹匀差额
        members.get(0).setSettlementAccountCny(members.get(0).getSettlementAccountCny().add(expOrder.getSettleAccountCny().subtract(totalSettlementAccountCny)).setScale(2,BigDecimal.ROUND_HALF_UP));
        expInvoiceNotification.setSettlementAmount(expOrder.getSettleAccountCny());
        expInvoiceNotification.setMembers(members);
        return expInvoiceNotification;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void taxBureauRegister(TaxBureauDTO dto) {
        PurchaseContract purchaseContract = super.getById(dto.getId());
        Optional.ofNullable(purchaseContract).orElseThrow(()->new ServiceException("采购合同信息不存在"));
        DomainStatus.getInstance().check(DomainOprationEnum.PURCHASE_TAX_BUREAU,purchaseContract.getStatusId());
        purchaseContract.setIsCorrespondence(dto.getIsCorrespondence());
        if(Objects.equals(purchaseContract.getIsCorrespondence(),Boolean.TRUE)){
            if(StringUtils.isEmpty(dto.getReplyStatus())){
                throw new ServiceException("请选择是否回函");
            }
            purchaseContract.setReplyStatus(dto.getReplyStatus());
            if("已回函".equals(purchaseContract.getReplyStatus()) && Objects.isNull(dto.getReplyDate())){
                throw new ServiceException("回函日期不能为空");
            }
            purchaseContract.setReplyDate(dto.getReplyDate());
        }else{
            purchaseContract.setReplyStatus("");
            purchaseContract.setReplyDate(null);
        }
        purchaseContract.setTaxDeclareTime(dto.getTaxDeclareTime());
        purchaseContract.setTaxDeclareAmount(dto.getTaxDeclareAmount());
        purchaseContract.setTaxRefundTime(dto.getTaxRefundTime());
        purchaseContract.setTaxRefundAmount(dto.getTaxRefundAmount());
        purchaseContract.setTaxRefundRemark(dto.getTaxRefundRemark());
        super.updateById(purchaseContract);
    }

    @Override
    public void sendMail(Long id,List<String> receivers) {
        PurchaseContract purchaseContract = super.getById(id);
        ValidatorUtils.isTrue(Objects.nonNull(purchaseContract),()->new ServiceException("采购合同信息不存在"));

        ExpOrder expOrder = expOrderService.findByDocNo(purchaseContract.getOrderNo());
        ValidatorUtils.isTrue(Objects.nonNull(expOrder),()->new ServiceException("采购合同对应的订单不存在"));

        Long fileId = contractPdf(id);
        //发送MQ消息发送邮件
        String title =  StrUtil.format("采购合同{}",purchaseContract.getDocNo());
        Map<String,Object> templateData = Maps.newHashMap();
        templateData.put("subjectName",purchaseContract.getBuyerName());
        templateData.put("sellerName",purchaseContract.getSellerName());
        templateData.put("contractNo",expOrder.getClientNo());
        mailService.sendSimpleWithMQByTemplate(receivers,title, MailContentTypeEnum.COMMON, MailTemplateTypeEnum.PURCHASE_CONTRACT,templateData,Collections.singletonList(fileId),Boolean.TRUE);
        //设为常用的邮箱
        String personName = SecurityUtil.getCurrentPersonName();
        String customerName = purchaseContract.getSellerName();
        String redisKey = "SCM:PURCHASE_CONTRACT:SENDMAIL";
        redisTemplate.opsForHash().put(redisKey,personName + "-" + customerName, String.join(",",receivers.toArray(new String[receivers.size()])));
    }

    @Override
    public Long contractPdf(Long id) {
        PurchaseContractPlusVO purchaseContractPlusVO = detailPlus(id,null);
        ExportFileDTO exportFileDTO =  generateContractPdf(purchaseContractPlusVO);
        Long fileId = exportFileService.save(exportFileDTO);
        return fileId;
    }

    @Override
    public String getDefaultMail(String customerName) {
        //设为常用的邮箱
        String personName = SecurityUtil.getCurrentPersonName();
        String redisKey = "SCM:PURCHASE_CONTRACT:SENDMAIL";
        return StringUtils.null2EmptyWithTrim(redisTemplate.opsForHash().get(redisKey,personName + "-" + customerName));
    }

    @Override
    public Long deliveryPdf(Long id) {
        PurchaseContractPlusVO purchaseContractPlusVO = detailPlus(id,null);
        ExportFileDTO exportFileDTO =  generateDeliveryPdf(purchaseContractPlusVO);
        Long fileId = exportFileService.save(exportFileDTO);
        return fileId;
    }

    public ExportFileDTO generateDeliveryPdf(PurchaseContractPlusVO purchaseContractPlusVO) {
        PurchaseContractVO purchaseContract = purchaseContractPlusVO.getPurchaseContract();
        List<PurchaseContractMemberVO> members = purchaseContractPlusVO.getMembers();
        //定义临时文件存放目录
        String path = filePath +"temp/"+ "scm" +"/purchaseContract/";
        String sysFileName = String.format("%s_%s.pdf",purchaseContract.getDocNo(), LocalDateTimeUtils.formatNow("yyyyMMddHHmmssSSS"));
        String fileName = String.format("%s_DELIVERY.pdf",purchaseContract.getCustomerOrderNo());
        ValidatorUtils.isTrueCall(!new File(path).exists(),()->new File(path).mkdirs());
        Document document = null;
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(path.concat(File.separator + sysFileName));
            BaseFont bfCN = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H",true);
            //标题的字体
            Font chFont = new Font(bfCN, 20, Font.NORMAL, BaseColor.BLACK);
            //正文的字体
            Font textFont = new Font(bfCN, 10, Font.NORMAL, BaseColor.BLACK);
            Rectangle rectangle = new Rectangle(PageSize.A4);
            document = new Document(rectangle);
            PdfWriter writer= PdfWriter.getInstance(document, out);
            document.open();
            //4.添加标题
            if(StringUtils.isNotEmpty(purchaseContract.getSellerName())){
                Paragraph  content = new Paragraph(purchaseContract.getSellerName(),textFont);
                content.setAlignment(Element.ALIGN_CENTER);
                document.add(content);
            }
            if(StringUtils.isNotEmpty(purchaseContract.getSellerBankAddress())){
                Paragraph  content = new Paragraph(purchaseContract.getSellerBankAddress(),textFont);
                content.setAlignment(Element.ALIGN_CENTER);
                document.add(content);
            }
            Paragraph  content = new Paragraph(String.format("电话：%s",(StringUtils.isNotEmpty(purchaseContract.getSellerTel())?purchaseContract.getSellerTel():"     ")),textFont);
            content.setAlignment(Element.ALIGN_CENTER);
            document.add(content);

            document.add(new Paragraph("   ",chFont));
            document.add(new Paragraph("   ",chFont));

            content = new Paragraph("送货单",chFont);
            content.setAlignment(Element.ALIGN_CENTER);
            document.add(content);

            LineSeparator line = new LineSeparator(1, 100, new BaseColor(204, 204, 204), Element.ALIGN_CENTER, 0);
            Paragraph p_line = new Paragraph("",textFont);
            p_line.add(line);
            document.add(p_line);
            document.add(new Paragraph(" ",textFont));
            document.add(new Paragraph(" ",textFont));
            PdfPTable table = new PdfPTable(4);
            table.getDefaultCell().setBorder(PdfPCell.NO_BORDER);
            table.setWidthPercentage(100);
            int[] array = {12, 38, 12, 38};
            table.setWidths(array);
            table.addCell(new Phrase("Doc No：",textFont));
            table.addCell(new Phrase(purchaseContract.getCustomerOrderNo(),textFont));
            table.addCell(new Phrase("Date：",textFont));
            table.addCell(new Phrase(DateUtils.formatShort(purchaseContract.getSigningDate()),textFont));

            table.addCell(new Paragraph("To：",textFont));
            table.addCell(new Paragraph(StringUtils.null2EmptyWithTrim(purchaseContract.getBuyerName()),textFont));
            table.addCell(new Paragraph("",textFont));
            table.addCell(new Paragraph("",textFont));

            document.add(table);

            document.add(new Paragraph(" ",textFont));
            PdfPTable productsTable = new PdfPTable(9);
            productsTable.setWidthPercentage(100);
            int[] productsArray = {5,16,10,20,8,5,9,11,6};
            productsTable.setWidths(productsArray);
            productsTable.addCell(new Phrase("行号",textFont));
            productsTable.addCell(new Phrase("品名",textFont));
            productsTable.addCell(new Phrase("品牌",textFont));
            productsTable.addCell(new Phrase("型号",textFont));
            productsTable.addCell(new Phrase("数量",textFont));
            productsTable.addCell(new Phrase("单位",textFont));
            productsTable.addCell(new Phrase("净重(KG)",textFont));
            productsTable.addCell(new Phrase("毛重(KG)",textFont));
            productsTable.addCell(new Phrase("件数",textFont));

            BigDecimal tquantity = members.stream().map(PurchaseContractMemberVO::getQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
            BigDecimal ttotalPrice = members.stream().map(PurchaseContractMemberVO::getTotalPrice).reduce(BigDecimal.ZERO,BigDecimal::add);
            BigDecimal tnetWeight = members.stream().map(PurchaseContractMemberVO::getNetWeight).reduce(BigDecimal.ZERO,BigDecimal::add).setScale(4,BigDecimal.ROUND_HALF_UP);
            BigDecimal tgrossWeight = members.stream().map(PurchaseContractMemberVO::getGrossWeight).reduce(BigDecimal.ZERO,BigDecimal::add).setScale(4,BigDecimal.ROUND_HALF_UP);
            Integer cartonNum = 0;
            for(int i= 0,length = members.size();i < length;i++) {
                PurchaseContractMemberVO member = members.get(i);
                productsTable.addCell(new Phrase(StringUtils.null2EmptyWithTrim(i + 1), textFont));
                productsTable.addCell(new Phrase(member.getName(), textFont));
                productsTable.addCell(new Phrase(member.getBrand().endsWith("牌") ? member.getBrand() : member.getBrand() + "牌", textFont));
                productsTable.addCell(new Phrase(member.getModel(), textFont));
                PdfPCell cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(member.getQuantity()), textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);
                productsTable.addCell(new Phrase(member.getUnitName(), textFont));

                cell = new PdfPCell(new Phrase(StringUtils.null2EmptyWithTrim(member.getNetWeight()), textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(StringUtils.null2EmptyWithTrim(member.getGrossWeight()), textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(StringUtils.null2EmptyWithTrim(member.getCartonNum()), textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);

                cartonNum += TypeUtils.castToInt(member.getCartonNum(),0);
            }


            PdfPCell cell = new PdfPCell(new Paragraph("合计Total：",textFont));
            cell.setColspan(4);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(tquantity),textFont));
            cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
            productsTable.addCell(cell);

            productsTable.addCell(new Phrase(" ",textFont));
            cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(tnetWeight),textFont));
            cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(tgrossWeight),textFont));
            cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase(StringUtils.null2EmptyWithTrim(cartonNum),textFont));
            cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
            productsTable.addCell(cell);

            document.add(productsTable);

            PdfPTable autographTable = new PdfPTable(4);
            autographTable.setWidthPercentage(100);
            autographTable.getDefaultCell().setBorder(PdfPCell.NO_BORDER);
            int[] autographArray = {15,35,15,35};
            autographTable.setWidths(autographArray);

            autographTable.addCell(new Phrase(" ",textFont));
            autographTable.addCell(new Phrase(" ",textFont));
            autographTable.addCell(new Phrase(" ",textFont));
            autographTable.addCell(new Phrase(" ",textFont));

            autographTable.addCell(new Phrase("送货单位：",textFont));
            autographTable.addCell(new Phrase(purchaseContract.getSellerName(),textFont));
            autographTable.addCell(new Phrase("收货单位：",textFont));
            autographTable.addCell(new Phrase(purchaseContract.getBuyerName(),textFont));

            autographTable.addCell(new Paragraph("盖章：",textFont));
            autographTable.addCell(new Paragraph(StringUtils.null2EmptyWithTrim(purchaseContract.getBuyerBankAddress()),textFont));
            autographTable.addCell(new Paragraph("盖章：",textFont));
            autographTable.addCell(new Paragraph(StringUtils.null2EmptyWithTrim(purchaseContract.getSellerBankAddress()),textFont));

            autographTable.addCell(new Paragraph("经手人：",textFont));
            autographTable.addCell(new Paragraph(StringUtils.null2EmptyWithTrim(purchaseContract.getBuyerTel()),textFont));
            autographTable.addCell(new Paragraph("经手人",textFont));
            autographTable.addCell(new Paragraph(StringUtils.null2EmptyWithTrim(purchaseContract.getSellerTel()),textFont));

            document.add(autographTable);

            document.close();
            out.flush();
            out.close();

            ExportFileDTO exportFileDTO = new ExportFileDTO();
            exportFileDTO.setPath(path.concat(File.separator).concat(sysFileName));
            exportFileDTO.setFileName(fileName);
            exportFileDTO.setOnce(Boolean.TRUE);
            exportFileDTO.setOperator("系统自动生成");
            return exportFileDTO;
        } catch (Exception e) {
            log.error("生成采购合同送货单PDF失败：",e);
            throw new ServiceException("生成合同PDF失败，请您稍后再试");
        } finally {
            if(document != null) {
                document.close();
            }
            if(out != null) {
                try {
                    out.close();
                } catch (IOException e) {

                }
            }
        }
    }

    public ExportFileDTO generateContractPdf(PurchaseContractPlusVO purchaseContractPlusVO) {
        PurchaseContractVO purchaseContract = purchaseContractPlusVO.getPurchaseContract();
        List<PurchaseContractMemberVO> members = purchaseContractPlusVO.getMembers();
        //定义临时文件存放目录
        String path = filePath +"temp/"+ "scm" +"/purchaseContract/";
        String sysFileName = String.format("%s_%s.pdf",purchaseContract.getDocNo(), LocalDateTimeUtils.formatNow("yyyyMMddHHmmssSSS"));
        String fileName = String.format("%s_CONTRACT.pdf",purchaseContract.getCustomerOrderNo());
        ValidatorUtils.isTrueCall(!new File(path).exists(),()->new File(path).mkdirs());
        Document document = null;
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(path.concat(File.separator + sysFileName));
            BaseFont bfCN = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H",true);
            //标题的字体
            Font chFont = new Font(bfCN, 20, Font.NORMAL, BaseColor.BLACK);
            //正文的字体
            Font textFont = new Font(bfCN, 10, Font.NORMAL, BaseColor.BLACK);
            Rectangle rectangle = new Rectangle(PageSize.A4);
            document = new Document(rectangle);
            PdfWriter writer= PdfWriter.getInstance(document, out);
            document.open();
            //4.添加标题
            Paragraph content = new Paragraph("采购合同",chFont);
            content.setAlignment(Element.ALIGN_CENTER);
            document.add(content);
            content = new Paragraph("PURCHASE CONTRACT",textFont);
            content.setAlignment(Element.ALIGN_CENTER);
            document.add(content);

            LineSeparator line = new LineSeparator(1, 100, new BaseColor(204, 204, 204), Element.ALIGN_CENTER, 0);
            Paragraph p_line = new Paragraph("",textFont);
            p_line.add(line);
            document.add(p_line);
            document.add(new Paragraph(" ",textFont));
            document.add(new Paragraph(" ",textFont));
            PdfPTable table = new PdfPTable(4);
            table.getDefaultCell().setBorder(PdfPCell.NO_BORDER);
            table.setWidthPercentage(100);
            int[] array = {12, 38, 12, 38};
            table.setWidths(array);
            table.addCell(new Phrase("签订日期：",textFont));
            table.addCell(new Phrase(DateUtils.formatShort(purchaseContract.getSigningDate()),textFont));
            table.addCell(new Phrase("合同编号：",textFont));
            table.addCell(new Phrase(StringUtils.null2EmptyWithTrim(purchaseContract.getDocNo()),textFont));

            table.addCell(new Paragraph("签订地点：",textFont));
            table.addCell(new Paragraph(StringUtils.null2EmptyWithTrim(purchaseContract.getSigningPlace()),textFont));
            table.addCell(new Paragraph("客户单号：",textFont));
            table.addCell(new Paragraph(StringUtils.null2EmptyWithTrim(purchaseContract.getCustomerOrderNo()),textFont));

            table.addCell(new Paragraph("买方：",textFont));
            table.addCell(new Paragraph(StringUtils.null2EmptyWithTrim(purchaseContract.getBuyerName()),textFont));
            table.addCell(new Paragraph("卖方：",textFont));
            table.addCell(new Paragraph(StringUtils.null2EmptyWithTrim(purchaseContract.getSellerName()),textFont));

            document.add(table);
            document.add(new Paragraph("根据《中华人民共和国合同法》及相关法律法规，本着平等自愿、等价有偿、诚实信用原则，经买卖双方同意由卖方售出买方购进如下货物，并按下列条款签订本合同：",textFont));
            document.add(new Paragraph("  ",textFont));


            document.add(new Paragraph("一、产品名称、规格、数量、金额",textFont));
            document.add(new Paragraph(" ",textFont));
            PdfPTable productsTable = new PdfPTable(9);
            productsTable.setWidthPercentage(100);
            int[] productsArray = {5,16,10,20,8,5,9,11,6};
            productsTable.setWidths(productsArray);
            productsTable.addCell(new Phrase("行号",textFont));
            productsTable.addCell(new Phrase("品名",textFont));
            productsTable.addCell(new Phrase("品牌",textFont));
            productsTable.addCell(new Phrase("型号",textFont));
            productsTable.addCell(new Phrase("数量",textFont));
            productsTable.addCell(new Phrase("单位",textFont));
            productsTable.addCell(new Phrase("单价",textFont));
            productsTable.addCell(new Phrase("总价",textFont));
            productsTable.addCell(new Phrase("币制",textFont));

            BigDecimal tquantity = members.stream().map(PurchaseContractMemberVO::getQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
            BigDecimal ttotalPrice = members.stream().map(PurchaseContractMemberVO::getTotalPrice).reduce(BigDecimal.ZERO,BigDecimal::add);
            for(int i= 0,length = members.size();i < length;i++) {
                PurchaseContractMemberVO member = members.get(i);
                productsTable.addCell(new Phrase(StringUtils.null2EmptyWithTrim(i + 1), textFont));
                productsTable.addCell(new Phrase(member.getName(), textFont));
                productsTable.addCell(new Phrase(member.getBrand().endsWith("牌") ? member.getBrand() : member.getBrand() + "牌", textFont));
                productsTable.addCell(new Phrase(member.getModel(), textFont));
                PdfPCell cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(member.getQuantity()), textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);
                productsTable.addCell(new Phrase(member.getUnitName(), textFont));
                cell = new PdfPCell(new Phrase(StringUtils.null2EmptyWithTrim(member.getUnitPrice()), textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);
                cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(member.getTotalPrice()), textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);
                productsTable.addCell(new Phrase("人民币", textFont));
            }

            PdfPCell cell = new PdfPCell(new Paragraph("合计：",textFont));
            cell.setColspan(4);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(tquantity),textFont));
            cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
            productsTable.addCell(cell);

            productsTable.addCell(new Phrase(" ",textFont));
            productsTable.addCell(new Phrase(" ",textFont));

            cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(ttotalPrice),textFont));
            cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
            productsTable.addCell(cell);

            productsTable.addCell(new Phrase(" ",textFont));

            document.add(productsTable);

            document.add(new Paragraph("二、质量及验货：按买卖双方约定的质量要求，符合出口质量标准，买方对货物的品名、品牌、型号、规格、数量等进行检验；",textFont));
            document.add(new Paragraph("三、包装方式：原厂包装；",textFont));
            document.add(new Paragraph("四、交货地点：按买、卖双方约定地点交货；",textFont));
            document.add(new Paragraph("五、付款方式及期限：买方收到境外客户的全部外汇款项后T/T支付货款。",textFont));
            document.add(new Paragraph(StrUtil.format("六、交货期：卖方须于{}前全部交货完毕；",DateUtils.format(purchaseContract.getDeliveryDate(),"yyyy-MM-dd")),textFont));
            document.add(new Paragraph("七、运输及保险：买方负责安排货物的运输及保险，相关费用按《物流报价单》执行；",textFont));
            document.add(new Paragraph(StrUtil.format("八、合同有效期：经双方盖章后生效，有效期至{}；",DateUtils.format(purchaseContract.getEffectiveDate(),"yyyy-MM-dd")),textFont));
            document.add(new Paragraph("九、解决合同争议：凡因执行本合同所发生的或与本合同有关的一切争议，应由双方通过友好协商解决。如协商不能解决，任何一方均可向本协议签订地人民法院提起诉讼解决。",textFont));
            document.add(new Paragraph("十、其它约定事项：无；",textFont));
            document.add(new Paragraph("十一、本合同一式贰份，双方各执一份。",textFont));

            PdfPTable autographTable = new PdfPTable(4);
            autographTable.setWidthPercentage(100);
            autographTable.getDefaultCell().setBorder(PdfPCell.NO_BORDER);
            int[] autographArray = {15,35,15,35};
            autographTable.setWidths(autographArray);

            autographTable.addCell(new Phrase(" ",textFont));
            autographTable.addCell(new Phrase(" ",textFont));
            autographTable.addCell(new Phrase(" ",textFont));
            autographTable.addCell(new Phrase(" ",textFont));

            autographTable.addCell(new Phrase("买方：",textFont));
            autographTable.addCell(new Phrase(purchaseContract.getBuyerName(),textFont));
            autographTable.addCell(new Phrase("卖方：",textFont));
            autographTable.addCell(new Phrase(purchaseContract.getSellerName(),textFont));

            autographTable.addCell(new Paragraph("地址：",textFont));
            autographTable.addCell(new Paragraph(StringUtils.null2EmptyWithTrim(purchaseContract.getBuyerBankAddress()),textFont));
            autographTable.addCell(new Paragraph("地址：",textFont));
            autographTable.addCell(new Paragraph(StringUtils.null2EmptyWithTrim(purchaseContract.getSellerBankAddress()),textFont));

            autographTable.addCell(new Paragraph("电话：",textFont));
            autographTable.addCell(new Paragraph(StringUtils.null2EmptyWithTrim(purchaseContract.getBuyerTel()),textFont));
            autographTable.addCell(new Paragraph("电话",textFont));
            autographTable.addCell(new Paragraph(StringUtils.null2EmptyWithTrim(purchaseContract.getSellerTel()),textFont));

            autographTable.addCell(new Phrase("开户行：",textFont));
            autographTable.addCell(new Phrase(StringUtils.null2EmptyWithTrim(purchaseContract.getBuyerBank()),textFont));
            autographTable.addCell(new Phrase("开户行：",textFont));
            autographTable.addCell(new Phrase(StringUtils.null2EmptyWithTrim(purchaseContract.getSellerBank()),textFont));

            autographTable.addCell(new Phrase("银行账号：",textFont));
            autographTable.addCell(new Phrase(StringUtils.null2EmptyWithTrim(purchaseContract.getBuyerBankNo()),textFont));
            autographTable.addCell(new Phrase("银行账号：",textFont));
            autographTable.addCell(new Phrase(StringUtils.null2EmptyWithTrim(purchaseContract.getSellerBankNo()),textFont));

            autographTable.addCell(new Phrase("签约代表：",textFont));
            autographTable.addCell(new Phrase(StringUtils.null2EmptyWithTrim(purchaseContract.getBuyerDeputy()),textFont));
            autographTable.addCell(new Phrase("签约代表：",textFont));
            autographTable.addCell(new Phrase(StringUtils.null2EmptyWithTrim(purchaseContract.getSellerDeputy()),textFont));

            document.add(autographTable);

            document.close();
            out.flush();
            out.close();

            ExportFileDTO exportFileDTO = new ExportFileDTO();
            exportFileDTO.setPath(path.concat(File.separator).concat(sysFileName));
            exportFileDTO.setFileName(fileName);
            exportFileDTO.setOnce(Boolean.TRUE);
            exportFileDTO.setOperator("系统自动生成");
            return exportFileDTO;
        } catch (Exception e) {
            log.error("生成采购合同PDF失败：",e);
            throw new ServiceException("生成合同PDF失败，请您稍后再试");
        } finally {
            if(document != null) {
                document.close();
            }
            if(out != null) {
                try {
                    out.close();
                } catch (IOException e) {

                }
            }
        }
    }

    //清空任务通知
    public void clearTaskNotice(Long id){
        taskNoticeContentService.deleteTaskNotice(DomainTypeEnum.PURCHASECONTRACT.getCode(), id, "");
    }
}
